#include <itemengine.h>
#include <librsvg/rsvg.h>
#include <librsvg/rsvg-cairo.h>
#include <gtk/gtk.h>
#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>

static gchar* engine_name = "appstarter";
static gchar* engine_description = "Simple Application Starter Item Engine";
static gchar* engine_author = "Michael Ewers <ewers@gmx.de>";
static gchar* engine_version = "0.1";
static gchar* keyfile_section_name = "Appstarter Settings";

static const guint ITEM_STATE_NONE = 1;
static const guint ITEM_STATE_INACTIVE = 2;
static const guint ITEM_STATE_ACTIVE = 3;
static const guint ITEM_STATE_LOADING = 4;
static const guint ITEM_STATE_PROBLEM = 5;

typedef struct _ItemData {
  cairo_surface_t* iconBuffer;
  guint state;
  gchar* execCommand;
  gchar* iconFilename;
} ItemData;

GHashTable* engine_item_data;
DockItemEngine* engine_udock_object;
DockInterface* udock;

void on_item_expose(DockItem*);
void on_item_redraw(DockItem*);
void on_item_mouse_enter(DockItem*);
void on_item_mouse_move(DockItem*,guint,guint);
void on_item_mouse_exit(DockItem*);
void on_item_mouse_down(DockItem*);
void on_item_mouse_up(DockItem*);
void on_item_mouse_scroll_up(DockItem*);
void on_item_mouse_scroll_down(DockItem*);
void on_item_mouse_rclick(DockItem*);
void on_item_mouse_dnd_drop(DockItem*,void*);
void engine_init(DockInterface*, DockItemEngine*); /* done */
cairo_surface_t* engine_item_render(DockItem*,cairo_t*); /* done */

void engine_item_init(gchar*,gchar*,gchar*,gchar*);
ItemData* engine_item_get_data(DockItem*);

cairo_surface_t* engine_render_svg(gchar*,cairo_t*);
cairo_surface_t* engine_render_png(gchar*,cairo_t*);

void (*udock_item_register)(DockItem*,DockItemEngine*);
void (*udock_item_request_redraw)(DockItem*);

void engine_init(DockInterface* dock, DockItemEngine* engine) {
  g_print("engine_init()\n");
  udock = dock;
  engine_item_data = g_hash_table_new(g_direct_hash, g_direct_equal);
  engine_udock_object = engine;

  gchar* desktop_dir = g_strconcat(getenv("HOME"), "/.udock/appstarter", NULL);
  DIR* dir;
  struct dirent *dirp;
  if ((dir = opendir(desktop_dir)) == NULL) {
    g_print("You need to create the following dir and put some *.desktop files in it: %s\n", desktop_dir);
  } else {
    while ((dirp = readdir(dir)) != NULL) {
      gchar* file_rel_fn = dirp->d_name;
      if (g_str_has_suffix(file_rel_fn, ".desktop")) {
	gchar* file_abs_fn = g_strconcat(desktop_dir, "/", file_rel_fn, NULL);
	GKeyFile* kf = g_key_file_new();
	g_key_file_load_from_file(kf, file_abs_fn, G_KEY_FILE_NONE, NULL);
	DockItem* item = g_new(DockItem, 1);
	ItemData* data = g_new(ItemData, 1);
	item->name = g_key_file_get_string(kf, "Desktop Entry", "Name", NULL);
	data->iconFilename = g_key_file_get_string(kf, "Desktop Entry", "Icon", NULL);
	data->execCommand = g_key_file_get_string(kf, "Desktop Entry", "Exec", NULL);
	data->state = ITEM_STATE_INACTIVE;

	item->description = g_key_file_get_string(kf, "Desktop Entry", "Description", NULL);

	g_hash_table_insert(engine_item_data, item, data);
	dock->dock_item_register_callback(item, engine_udock_object);
	g_print("item initialized: %s\n", item->name);
      }
    }
  }
  
}

void engine_item_init(gchar* name, gchar* icon_filename, gchar* description, gchar* execCommand) {
  DockItem* item = g_new(DockItem, 1);
  item->name = g_strdup(name);
  item->icon_filename = g_strdup(icon_filename);
  item->description = g_strdup(description);
  
  ItemData* item_data = g_new(ItemData, 1);
  item_data->state = ITEM_STATE_NONE;
  item_data->iconBuffer = NULL;
  item_data->execCommand = execCommand;
  item_data->iconFilename = icon_filename;
  g_hash_table_insert(engine_item_data, item, item_data);

  udock_item_register(item, engine_udock_object);
}

ItemData* engine_icon_get_data(DockItem* item) {
  return (ItemData*) g_hash_table_lookup(engine_item_data, item);
}

gchar* engine_get_name() {
  return engine_name;
}

gchar* engine_get_description() {
  return engine_description;
}

gchar* engine_get_author() {
  return engine_author;
}

gchar* engine_get_version() {
  return engine_version;
}

cairo_surface_t* engine_item_render(DockItem* item, cairo_t* cr) {
  ItemData* item_data = g_hash_table_lookup(engine_item_data, item);
  gchar* icon_filename = item_data->iconFilename;
  if (g_str_has_suffix(icon_filename, ".svg")) {
    return engine_render_svg(icon_filename, cr);
  }
  if (g_str_has_suffix(icon_filename, ".png")) {
    return engine_render_png(icon_filename, cr);
  }
  return NULL;
}

cairo_surface_t* engine_render_svg(gchar* filename, cairo_t* cr) {
  g_print("engine_render_svg\n");
  
  guint max_width = udock->default_item_width;
  guint max_height = udock->default_item_height;

  GError* error;
  RsvgHandle* handle = rsvg_handle_new_from_file(filename, &error);
  if (handle == NULL) {
    g_print("error reading svg: %s\n", filename);
    return NULL;
  }
  RsvgDimensionData dimensions;
  rsvg_handle_get_dimensions(handle, &dimensions);
  guint source_width = dimensions.width;
  guint source_height = dimensions.height;

  g_print("%i\t%i\n", source_width, source_height);

  gdouble max_source_width_rel = (gdouble) max_width / (gdouble) source_width;
  gdouble max_source_height_rel = (gdouble) max_height / (gdouble) source_height;
  
  gdouble scale_factor;
  if (max_source_width_rel < max_source_height_rel)
    scale_factor = max_source_width_rel;
  else
    scale_factor = max_source_height_rel;

  guint target_width = (guint) (source_width * scale_factor);
  guint target_height = (guint) (source_height * scale_factor);

  guint offset_x = 0, offset_y = 0;

  if (target_width < max_width)
    offset_x = (guint) ((max_width - target_width) / 2.0);
  if (target_height < max_height)
    offset_y = (guint) ((max_height - target_height) / 2.0);

  cairo_surface_t* targetSurface = cairo_get_target(cr);
  cairo_surface_t* sourceSurface;
  if (udock->alpha) {
    sourceSurface = cairo_surface_create_similar(targetSurface, CAIRO_CONTENT_COLOR_ALPHA, max_width, max_height);
  } else {
    sourceSurface = cairo_surface_create_similar(targetSurface, CAIRO_CONTENT_COLOR, max_width, max_height);
  }

  cairo_t* sourceCr = cairo_create(sourceSurface);
  cairo_save(sourceCr);
  cairo_set_operator(sourceCr, CAIRO_OPERATOR_SOURCE);
  cairo_set_source_rgb(sourceCr, 255, 255, 255);
  cairo_paint(sourceCr);
 
  cairo_restore(sourceCr);

  cairo_set_operator(sourceCr, CAIRO_OPERATOR_OVER);
  cairo_scale(sourceCr, scale_factor, scale_factor);
  rsvg_handle_render_cairo(handle, sourceCr);

  cairo_destroy(sourceCr);

  return sourceSurface;
}

cairo_surface_t* engine_render_png(gchar* filename, cairo_t* cr) {
  return NULL;
}

void on_item_expose(DockItem* item) {

}
void on_item_redraw(DockItem* item) {

}
void on_item_mouse_enter(DockItem* item) {

}
void on_item_mouse_move(DockItem* item, guint mouse_x, guint mouse_y) {
  g_print("%i\t%i\n", mouse_x, mouse_y);
}
void on_item_mouse_exit(DockItem* item) {

}
void on_item_mouse_down(DockItem* item) {
  g_print("mouse_down\n");
}
void on_item_mouse_up(DockItem* item) {

}
void on_item_mouse_scroll_up(DockItem* item) {

}
void on_item_mouse_scroll_down(DockItem* item) {

}
void on_item_mouse_rclick(DockItem* item) {

}
void on_item_mouse_dnd_drop(DockItem* item,void* object) {

}
